package vh.sphynx.runtime.impl;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import vh.sphynx.util.ReflectionUtil;
import vh.sphynx.util.SphynxRuntimeUtil;

public class FindTextLocator extends AbstractTextLocator {

	public static final int OP_NOOP = 0;
	public static final int OP_EQUAL = 1;
	public static final int OP_CLOSE_TAG = 2;
	public static final int OP_MATCH = 3;
	
	protected Matcher matcher;
	protected String matchedText;
	protected int length;
		
	@Override
	public int locate(CharSequence input, int sidx, String pattern, int patternFlag, int operator, boolean lastPosOnUnmatch, Map<String, Integer> groups) {
		StringBuffer buffer = null;
		int result = -1;
		String value = pattern;
		length = 0;
		matchedText = null;
		
		switch(operator) {
		case OP_EQUAL:
			 buffer = new StringBuffer(input);
			 result = buffer.indexOf(value, sidx);
			 length = value.length();
			 matchedText = result >= 0 ? value : null;
			break;
		case OP_MATCH:
			Pattern pat = SphynxRuntimeUtil.compilePattern(pattern, patternFlag);
			matcher = pat.matcher(sidx > 0 ? input.subSequence(sidx, input.length()) : input);
			if (matcher.find()) {
				result = sidx + matcher.start();
				length = matcher.group().length();
				matchedText = matcher.group();
				this.fields = groups;
			}
			else
				matcher = null;
			break;
		case OP_CLOSE_TAG:
			String endtag = "</" + value + ">";
			String begtag = "<" + value;
			buffer = new StringBuffer(input);
			result = buffer.indexOf(endtag, sidx);
			while (result >= 0) {
				int begTagCount = 0;
				int tempSidx = sidx;
				while ((tempSidx = buffer.indexOf(begtag, sidx)) >= 0 && tempSidx < result) {
					begTagCount++;
					sidx = tempSidx + 1;
				}

				for (int i = 0; i < begTagCount && result >= 0; i++)
					result = buffer.indexOf(endtag, result + 1);

				if (begTagCount == 0) break;
			}

			length = endtag.length();
			matchedText = endtag; 
			break;
		}
		if (result == -1 && lastPosOnUnmatch)
			result = input.length();
		return result;
	}

	@Override
	public int getLength() {
		return length;
	}

	@Override
	public boolean isMatched() {
		return matchedText != null;
	}

	@Override
	protected Object basicGetMember(int idx) {
		if (isMatched() && idx <= matcher.groupCount())
			return matcher.group(idx);
		return null;
	}

	@Override
	public boolean hasMember(String name) {
		return fields != null && fields.containsKey(name);
	}

	@Override
	public boolean hasMember(Object... indecies) {
		return indecies.length == 1 && (
				(indecies[0] instanceof String) || ReflectionUtil.isIntegerNumber(indecies[0]));
	}
}
